﻿using System;
using System.Data;
using System.Data.Common;
using System.Xml;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;

namespace MSP.Data.NHibernate.UserType
{
	public class XmlType : IUserType
	{
		public new bool Equals(object x, object y)
		{
			if (x == null || y == null) return false;
			var xdoc_x = (XmlDocument) x;
			var xdoc_y = (XmlDocument) y;
			return xdoc_y.OuterXml == xdoc_x.OuterXml;
		}

		public int GetHashCode(object x)
		{
			return x.GetHashCode();
		}

		public object NullSafeGet(IDataReader rs, string[] names, object owner)
		{
			if (names.Length != 1)
				throw new InvalidOperationException("names array has more than one element. can't handle this!");
			var document = new XmlDocument();
			var val = rs[names[0]] as string;

			if (val != null)
			{
				document.LoadXml(val);
				return document;
			}

			return null;
		}

		public void NullSafeSet(IDbCommand cmd, object value, int index)
		{
			var parameter = (DbParameter) cmd.Parameters[index];
			((DbParameter) parameter).DbType = DbType.Xml;
			
            if (value == null)
				parameter.Value = DBNull.Value;
            else
    			parameter.Value = ((XmlDocument) value).OuterXml;
		}

		public object DeepCopy(object value)
		{
			var toCopy = value as XmlDocument;
			if (toCopy == null) return null;

			var copy = new XmlDocument();
			copy.LoadXml(toCopy.OuterXml);
			return copy;
		}

		public object Replace(object original, object target, object owner)
		{
            return original;
		}

		public object Assemble(object cached, object owner)
		{
			var str = cached as string;
			if (str != null)
			{
				var doc = new XmlDocument();
				doc.LoadXml(str);
				return doc;
			}
			else
			{
				return null;
			}
		}

		public object Disassemble(object value)
		{
			var val = value as XmlDocument;
			if (val != null)
			{
				return val.OuterXml;
			}
			else
			{
				return null;
			}
		}

		public SqlType[] SqlTypes
		{
			get { return (new SqlType[] {new StringClobSqlType()}); }
		}

		public Type ReturnedType
		{
			get { return typeof (XmlDocument); }
		}

		public bool IsMutable
		{
			get { return true; }
		}
	}
}